﻿using UnityEngine;
using System.Collections;
using UnityEditor;
using System.IO;
using System.Text;
using System;
using SGUI;
using System.Collections.Generic;
namespace SGUIEditor
{
    public class AtlasAssetPostprocessor : AssetPostprocessor
    {
        void OnPreprocessTexture()
        {
            SGUIConfig.LoadConfig();
            AutoAtlasBuilder.Run();
        }
    }

    [InitializeOnLoad]
    public class StartupAutoAtlas
    {
        static bool HasChange = false;
        static StartupAutoAtlas()
        {
            if (EditorApplication.timeSinceStartup < 5)
            {
                //FileWatch
                string AtlasSrcPath = Application.dataPath + "/" + SGUIConfig.Get("AtlasSrcPath");
                FileSystemWatcher fileWatch = new FileSystemWatcher(AtlasSrcPath);
                fileWatch.Deleted += fileWatch_Deleted;
                fileWatch.IncludeSubdirectories = true;
                fileWatch.EnableRaisingEvents = true;
                //Update
                EditorApplication.update += Update;
                AutoAtlasBuilder.Run();
            }
        }

        public static void Update()
        {
            if (HasChange) 
            {
                AutoAtlasBuilder.Run();
                HasChange = false;
            }
        }
        static void fileWatch_Deleted(object sender, FileSystemEventArgs e)
        {
            HasChange = true;
        }
    }

    public static class AutoAtlasBuilder
    {
        [MenuItem("SGUI/Update Atlas")]
        public static void Update_Atlas() 
        {
            SGUIConfig.LoadConfig();
            ReGenAll();
           //Run();
        }

        static string AtlasSrcPath;
        static string AtlasGenPath;
        public static void Run() 
        {
            AtlasSrcPath = Application.dataPath + "/" + SGUIConfig.Get("AtlasSrcPath");
            AtlasGenPath = Application.dataPath + "/" + SGUIConfig.Get("AtlasGenPath");

            //顶层文件夹不存在全部生成.
            if (!Directory.Exists(AtlasGenPath))
            {
                Directory.CreateDirectory(AtlasGenPath);
                AssetDatabase.Refresh();
                ReGenAll();
            }
            //遍历源文件夹.
            DirectoryInfo GenAtlasFolder = new DirectoryInfo(AtlasSrcPath);
            DirectoryInfo[] atlasDirInfos = GenAtlasFolder.GetDirectories();
            for (int i = 0; i < atlasDirInfos.Length;i++)
            {
                
                if (AtlasFolderChange(atlasDirInfos[i].Name)) 
                {
                    GenFolderToAtlas(atlasDirInfos[i].Name);
                }
            }

        }

        static void ReGenAll()
        {
            AtlasSrcPath = Application.dataPath + "/" + SGUIConfig.Get("AtlasSrcPath");
            AtlasGenPath = Application.dataPath + "/" + SGUIConfig.Get("AtlasGenPath");
            //全部生成.
            DirectoryInfo GenPathDir = new DirectoryInfo(AtlasSrcPath);
            DirectoryInfo[] dirInfos = GenPathDir.GetDirectories();
            for (int i = 0; i < dirInfos.Length; i++)
            {
                GenFolderToAtlas(dirInfos[i].Name);
            }
        }
        static void GenFolderToAtlas(string folderPath) 
        {
            string assetsGenPath = SGUIConfig.Get("AtlasGenPath");
            DirectoryInfo SpriteFolder = new DirectoryInfo(AtlasSrcPath +"/"+ folderPath);
            FileInfo[] spriteFiles = SpriteFolder.GetFiles("*.png");
            Texture2D BigTex = new Texture2D(2048,2048);
           
            //Gen Atlas Png
            Texture2D[] lstTex2d = new Texture2D[spriteFiles.Length];
            for (int i = 0; i < spriteFiles.Length;i++)
            {
                string filePath =AtlasSrcPath +"/" + folderPath + "/" + spriteFiles[i].Name;
                byte[] texbuffer =  File.ReadAllBytes(filePath);
                Texture2D tex2d = new Texture2D(100,100);
                tex2d.LoadImage(texbuffer);
                lstTex2d[i] = tex2d;
            }
            Rect[] rects = BigTex.PackTextures(lstTex2d,5); 
            File.WriteAllBytes(AtlasGenPath+"/"+folderPath+"_Tex.png",BigTex.EncodeToPNG());
            //Gen Atlas Sprite 
            StreamWriter w = File.CreateText(AtlasGenPath + "/" + folderPath+"_Sprites.txt");
            for (int i = 0; i < rects.Length;i++)
            {
                rects[i] = ConvertToPixels(rects[i],BigTex.width,BigTex.height,true);
                w.WriteLine(spriteFiles[i].Name.Split('.')[0] + " " + rects[i].x.ToString() + " " + rects[i].y.ToString() + " " + rects[i].width.ToString() + " " + rects[i].height.ToString());
            }
            w.Flush();
            w.Close();
            //Set Png Setting
            AssetDatabase.Refresh();
            TextureImporter ti = AssetImporter.GetAtPath("Assets/" + assetsGenPath + "/" + folderPath + "_Tex.png") as TextureImporter;
            TextureImporterSettings settings = new TextureImporterSettings();
            ti.ReadTextureSettings(settings);
            settings.readable = false;
            settings.maxTextureSize = 4096;
            settings.wrapMode = TextureWrapMode.Clamp;
            settings.npotScale = TextureImporterNPOTScale.ToNearest;
            settings.textureFormat = TextureImporterFormat.ARGB32;
            settings.filterMode = FilterMode.Trilinear;
            settings.aniso = 4;
            ti.SetTextureSettings(settings);
            
            string AllStrMd5 = GenFolderMd5(folderPath);
            File.WriteAllText(AtlasGenPath + "/" + folderPath + "_md5.txt", AllStrMd5); 
            AssetDatabase.Refresh();
        }
        static string GenFolderMd5(string folderPath) 
        {
            string AllStrMd5 =""; 
            DirectoryInfo SpriteFolder = new DirectoryInfo(AtlasSrcPath + "/" + folderPath);
            FileInfo[] spriteFiles = SpriteFolder.GetFiles("*.png");
            for (int i = 0; i < spriteFiles.Length; i++)
            {
                string filePath = AtlasSrcPath + "/" + folderPath + "/" + spriteFiles[i].Name;
                string StrMd5 =  GetMD5HashFromFile(filePath);
                AllStrMd5 += StrMd5 + spriteFiles[i].Name;
            }
            return AllStrMd5;
           
        }
        static bool AtlasFolderChange(string folderName) 
        {
            if (!File.Exists(AtlasGenPath + "/" + folderName + ".png") || !File.Exists(AtlasGenPath + "/" + folderName + "_md5.txt")) 
            {
                return true;
            }
            string CacheMd5 = File.ReadAllText(AtlasGenPath + "/" + folderName + "_md5.txt");
            string NewFolderMd5 = GenFolderMd5(folderName);
            if (CacheMd5 != NewFolderMd5) 
            {
                return true;
            }
            return false;
        }

        private static string GetMD5HashFromFile(string fileName)
        {
            try
            {
                FileStream file = new FileStream(fileName, FileMode.Open);
                System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
                byte[] retVal = md5.ComputeHash(file);
                file.Close();

                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < retVal.Length; i++)
                {
                    sb.Append(retVal[i].ToString("x2"));
                }
                return sb.ToString();
            }
            catch (Exception ex)
            {
                throw new Exception("GetMD5HashFromFile() fail,error:" + ex.Message);
            }
        }

        static public Rect ConvertToPixels(Rect rect, int width, int height, bool round)
        {
            Rect final = rect;

            if (round)
            {
                final.xMin = Mathf.RoundToInt(rect.xMin * width);
                final.xMax = Mathf.RoundToInt(rect.xMax * width);
                final.yMin = Mathf.RoundToInt((1f - rect.yMax) * height);
                final.yMax = Mathf.RoundToInt((1f - rect.yMin) * height);
            }
            else
            {
                final.xMin = rect.xMin * width;
                final.xMax = rect.xMax * width;
                final.yMin = (1f - rect.yMax) * height;
                final.yMax = (1f - rect.yMin) * height;
            }
            return final;
        }

    }
}